import static java.lang.StrictMath.PI;
import static java.lang.StrictMath.abs;
import model.Game;
import model.Hockeyist;
import model.Move;
import model.Puck;
import model.Unit;
import model.World;


/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 * @author Constantine
 */
public class Moving {

    private static Hockeyist self;
    private static World world;
    private static Game game;
    private static Move move;

    public static void init(Hockeyist self, World world, Game game, Move move) {
        Moving.self = self;
        Moving.world = world;
        Moving.game = game;
        Moving.move = move;
    }

    public static double getSpeed(Unit unit) {
        return Math.hypot(unit.getSpeedX(), unit.getSpeedY());
    }

    public static boolean to(Point point, Unit turnTo) {
        if (self.getDistanceTo(point) < point.getRadius()) {
            if (turnTo != null) {
                move.setTurn(self.getAngleTo(turnTo));
            }
            return true;
        } else if (intersection(self, point, point.getRadius(), 50, 0.0d, 0.0d) != -1) {
            move.setTurn(self.getAngleTo(point));
        } else {
            move.setTurn(self.getAngleTo(point));
            if (abs(abs(Math.atan2(self.getSpeedY(), self.getSpeedX())) - abs(self.getAngle())) > 10 * PI / 180
                    && abs(self.getAngleTo(point)) > 2 * PI / 180) {
                move.setSpeedUp(0.3d);
            } else {
                move.setSpeedUp(1.0d);
            }
        }
        return false;
    }

    public static void to(Puck puck) {
        double ticks = 0;
        Unit puckCopy = cast(puck, null, 0.0d, 0);
        while (ticks < 200) {
            for (double a = 1.0d; a >= 0; a--) {
                Unit selfCopy = cast(self, puckCopy, a, ticks);
                if (atStickSector(selfCopy, puckCopy)) {
                    move.setSpeedUp(a);
                    move.setTurn(self.getAngleTo(puckCopy));
                    return;
                }
                selfCopy = cast(self, puckCopy, -a, ticks);
                if (atStickSector(selfCopy, puckCopy)) {
                    move.setSpeedUp(-a);
                    move.setTurn(self.getAngleTo(puckCopy));
                    return;
                }
            }
            puckCopy = cast(puckCopy, null, 0.0d, 1);
            ticks++;
        }
        move.setTurn(self.getAngleTo(puck));
        move.setSpeedUp(1.0d);
    }

    public static boolean atStickSector(Unit stickOwner, Unit unit) {
        return stickOwner.getDistanceTo(unit) < game.getStickLength() && abs(stickOwner.getAngleTo(unit)) < game.getStickSector() / 2;
    }

    private static double intersection(Unit unit1, Unit unit2, double radius, double maxTicks, double a1, double a2) {
        double tick = 0;
        Unit copy1 = cast(unit1, world.getPuck(), a1, tick);
        Unit copy2 = cast(unit2, null, a2, tick);

        do {
            if (copy1.getDistanceTo(copy2) < radius) {
                return tick;
            }
            copy1 = cast(copy1, copy2, a1, 1);
            copy2 = cast(copy2, null, a2, 1);
            tick++;
        } while (tick <= maxTicks);
        return -1;
    }

    public static Unit cast(Unit castUnit, Unit moveTo, double a, double ticks) {
        if (castUnit instanceof Hockeyist && abs(a) > ((Hockeyist) castUnit).getStamina() / game.getHockeyistMaxStamina()) {
            a = Math.signum(a) * ((Hockeyist) castUnit).getStamina() / game.getHockeyistMaxStamina();
        }
        Unit copy = HelpObject.copy(castUnit, castUnit.getX(), castUnit.getY(), castUnit.getSpeedX(), castUnit.getSpeedY(), castUnit.getAngle(), castUnit.getAngularSpeed());
        double tick = 0;
        while (tick < ticks) {
            tick++;
            double maxAngle = 0;
            if (moveTo != null) {
                if (a < 0) {
                    maxAngle = 0 - copy.getAngleTo(moveTo);
                } else {
                    maxAngle = copy.getAngleTo(moveTo);
                }
                if (abs(maxAngle) > game.getHockeyistTurnAngleFactor()) {
                    maxAngle = Math.signum(maxAngle) * game.getHockeyistTurnAngleFactor();
                }
            }
            double anglarSpeed = 0;
            if (abs(copy.getAngularSpeed()) >= 0.0270190131) {
                anglarSpeed = abs(copy.getAngularSpeed()) - 0.0270190131;
                anglarSpeed *= Math.signum(copy.getAngularSpeed());
            }
            double newAngle = copy.getAngle() + maxAngle + anglarSpeed;
            double newSpeedX = (copy.getSpeedX() + Math.cos(newAngle) * (a * (a > 0 ? 12500d : 7500) / 60d / 60d / copy.getMass())) * (copy.getMass() == world.getPuck().getMass() && world.getPuck().getOwnerPlayerId() == -1 ? 0.99899996581 : 0.98d);
            double newSpeedY = (copy.getSpeedY() + Math.sin(newAngle) * (a * (a > 0 ? 12500d : 7500) / 60d / 60d / copy.getMass())) * (copy.getMass() == world.getPuck().getMass() && world.getPuck().getOwnerPlayerId() == -1 ? 0.99899996581 : 0.98d);
            if (copy.getMass() == world.getPuck().getMass()
                    && (copy.getX() < Coords.X_MIN || copy.getX() > Coords.X_MAX
                    || copy.getY() < Coords.Y_MIN || copy.getY() > Coords.Y_MAX)) {
                double newX = copy.getX();
                double newY = copy.getY();
                if (copy.getX() < Coords.X_MIN || copy.getX() > Coords.X_MAX) {
                    newSpeedX = -newSpeedX * 0.25;
                    if (copy.getX() < Coords.X_MIN) {
                        newX = Coords.X_MIN - 0.2 * (copy.getX() - Coords.X_MIN);
                    } else {
                        newX = Coords.X_MAX - 0.2 * (copy.getX() - Coords.X_MAX);
                    }
                }
                if (copy.getY() < Coords.Y_MIN || copy.getY() > Coords.Y_MAX) {
                    newSpeedY = -newSpeedY * 0.25;
                    if (copy.getY() < Coords.Y_MIN) {
                        newY = Coords.Y_MIN - 0.2 * (copy.getY() - Coords.Y_MIN);
                    } else {
                        newY = Coords.Y_MAX - 0.2 * (copy.getY() - Coords.Y_MAX);
                    }
                }
                copy = HelpObject.copy(copy, newX + newSpeedX,
                                       newY + newSpeedY,
                                       newSpeedX,
                                       newSpeedY,
                                       newAngle,
                                       anglarSpeed);
            } else {
                copy = HelpObject.copy(copy, copy.getX() + newSpeedX,
                                       copy.getY() + newSpeedY,
                                       newSpeedX,
                                       newSpeedY,
                                       newAngle,
                                       anglarSpeed);
            }
        }
        return copy;
    }

    public static void moveByAttackLine(Point net) {
        double netY = Coords.getY(net.getY());
        double netX = Coords.getX(net.getX());
        double b = netY - netX;
        if (netY > 0) {
            b = -b;
        }

        double pX = Coords.getX(self.getX()) - Moving.getSpeed(self) / game.getHockeyistMaxSpeed();
        double pY = (pX - netX) * (b - netY) / (0 - netX) + netY;
        if (abs(pY) > 0.8) {
            pY = Math.signum(pY) * 0.85d;
        }

        Point newPoint = Point.getPoint(pX, pY);
        move.setTurn(self.getAngleTo(newPoint));
        move.setSpeedUp(1.0d);
    }

    static void moveByDefendLine(Point defenedPoint) {

        double netY = Coords.getY(defenedPoint.getY());
        double netX = Coords.getX(defenedPoint.getX());
        netY = Math.signum(netY) * 0.0001;
        netX = 0.81d;

        if (self.getDistanceTo(Point.getPoint(netX, netY)) < self.getRadius()) {
            move.setTurn(self.getAngleTo(world.getPuck()));
            return;
        }

        double b = netY - netX;
        if (netY < 0) {
            b = -b;
        }

        double pX = Coords.getX(self.getX()) + Moving.getSpeed(self) / game.getHockeyistMaxSpeed();
        if (pX > netX) {
            pX = netX;
        }
        double pY = (pX - netX) * (b - netY) / (0 - netX) + netY;

        if (abs(pY) > 0.5d) {
            pY = Math.signum(pY) * 0.6d;
        }

        Point newPoint = Point.getPoint(pX, pY);

        double angle = self.getAngleTo(newPoint);
        double moduleA = (self.getDistanceTo(Point.getPoint(netX, netY)) > self.getRadius() * 3) ? 1.0d : 0.3d;
        if (self.getDistanceTo(Point.getPoint(netX, netY)) > self.getRadius() * 8
                || self.getDistanceTo(Point.getPoint(netX, netY)) < self.getRadius() && abs(self.getAngleTo(Point.getPoint(netX, netY))) < PI / 2) {
            move.setTurn(angle);
            move.setSpeedUp(moduleA);
        } else {
            move.setTurn(-Math.signum(angle) * PI - angle);
            move.setSpeedUp(-moduleA);
        }
    }
}
